package com.inspur.dgov.vlbod.service.impl;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.timingwheel.SystemTimer;
import cn.hutool.cron.timingwheel.TimerTask;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.inspur.dgov.vlbod.constant.ServiceConstant;
import com.inspur.dgov.vlbod.entity.*;
import com.inspur.dgov.vlbod.helper.XyVideoHelper;
import com.inspur.dgov.vlbod.helper.model.XyLiveVideo;
import com.inspur.dgov.vlbod.helper.model.XyMeetingRoom;
import com.inspur.dgov.vlbod.mapper.LiveBroadcastMapper;
import com.inspur.dgov.vlbod.secure.token.UserRecord;
import com.inspur.dgov.vlbod.service.*;
import com.inspur.dgov.vlbod.util.CTools;
import com.inspur.dgov.vlbod.util.Secures;
import com.inspur.dgov.vlbod.vo.LiveBroadcastVO;
import com.inspur.dgov.vlbod.weixin.WeiXinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author chiyupei
 * @since 2023-05-28
 */
@Service
public class LiveBroadcastServiceImpl extends ServiceImpl<LiveBroadcastMapper, LiveBroadcast> implements LiveBroadcastService {

    @Resource
    private LiveBroadcastMapper liveBroadcastMapper;

    @Autowired
    private LiveCollectService liveCollectService;

    @Autowired
    private LiveThumbsUpService liveThumbsUpService;

    @Autowired
    private LiveShareService liveShareService;

    @Autowired
    private LiveVideoPullurlsService liveVideoPullurlsService;

    @Autowired
    private XyVideoHelper xyVideoHelper;

    @Autowired
    private WeiXinService weiXinService;

    @Value("${dgov.xyvideo.server.host}")
    private String xyApiHost;

    @Value("${dgov.xyvideo.server.http-port}")
    private Integer xyApiServerHttpPort;

    @Value("${dgov.xyvideo.server.https-port}")
    private Integer xyApiServerHttpsPort;

    private SystemTimer deplayStartLiveTaskTimer;

    @PostConstruct
    public void init(){
        deplayStartLiveTaskTimer = new SystemTimer();
        deplayStartLiveTaskTimer.start();
    }

    /**
     * 获取我的直播列表
     * @param page
     * @param data
     * @return
     */
    @Override
    //@Cacheable(value = "broadcastList",key = "'queryMyList' + '@' +#page.current +#page.size +#data")
    public Page<LiveBroadcastVO> queryMyList(Page<LiveBroadcastVO> page, JSONObject data) {
        return this.liveBroadcastMapper.queryMyList(page, data);
    }

    /**
     * 获取我的收藏列表
     * @param page
     * @param data
     * @return
     */
    @Override
    public Page<LiveBroadcastVO> queryCollectList(Page<LiveBroadcastVO> page, JSONObject data) {
        return this.liveBroadcastMapper.queryCollectList(page, data);
    }

    /**
     * 获取直播列表
     * @param page
     * @param data
     * @return
     */
    @Override
    public Page<LiveBroadcastVO> queryList(Page<LiveBroadcastVO> page, JSONObject data) {
//        // 获取当前时间
//        LocalDateTime now = LocalDateTime.now();
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//        LocalDateTime minus24Hrs = now.minusHours(24);
//        String minus24HrsStr = minus24Hrs.format(formatter);
//        data.put("minus24HrsStr",minus24HrsStr);
        return this.liveBroadcastMapper.queryList(page, data);
    }

    /**
     * 直播信息新增保存
     * @param data
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LiveBroadcast saveLiveBroadcast(LiveBroadcast data) throws RuntimeException {
        // 先创建小鱼视频会议室
        XyMeetingRoom meetingRoom = xyVideoHelper.createMeetingRoom(data);
        if (null == meetingRoom) {
            log.error("创建会议室失败");
            throw new RuntimeException("创建会议室失败");
        }
        data.setMeetingRoomNumber(meetingRoom.getMeetingNumber());
        // 创建直播
        XyLiveVideo xyLiveVideo = xyVideoHelper.createLiveBroadcast(data);
        if (null == xyLiveVideo) {
            log.error("创建直播失败");
            // 删除创建的会议室
            xyVideoHelper.deleteMeetingRoom(meetingRoom.getMeetingNumber());
            throw new RuntimeException("创建直播失败");
        }
        data.setLiveId(xyLiveVideo.getLiveId());
        data.setExtrasConfig(xyLiveVideo.getExtras());
        // 保存直播信息
        this.save(data);
        // 保存直播视频信息
        List<LiveVideoPullurls> pullUrlsList = xyLiveVideo.getPullUrls();
        for (LiveVideoPullurls videoPullurl : pullUrlsList) {
            videoPullurl.setId(CTools.getSnowflakeId());
            videoPullurl.setBroadcastId(data.getId());
        }
        this.liveVideoPullurlsService.saveBatch(pullUrlsList);
        return data;
    }

    /**
     * 直播信息修改保存
     * @param data
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LiveBroadcast updateLiveBroadcast(LiveBroadcast data) throws RuntimeException {
        if(!xyVideoHelper.updateMeetingRoom(data)){
            log.error("修改会议室失败");
            throw new RuntimeException("修改会议室失败");
        }
        // 修改直播
        XyLiveVideo xyLiveVideo = xyVideoHelper.updateLiveBroadcast(data);
        if (null == xyLiveVideo) {
            log.error("修改直播失败");
            throw new RuntimeException("修改直播失败");
        }
        data.setLiveId(xyLiveVideo.getLiveId());
        data.setExtrasConfig(xyLiveVideo.getExtras());
        // 修改直播信息
        this.updateById(data);
        // 删除直播视频信息
        this.liveVideoPullurlsService.remove(new LambdaQueryWrapper<LiveVideoPullurls>().eq(LiveVideoPullurls::getBroadcastId, data.getId()));
        // 新增直播视频信息
        List<LiveVideoPullurls> pullUrlsList = xyLiveVideo.getPullUrls();
        for (LiveVideoPullurls videoPullurl : pullUrlsList) {
            videoPullurl.setId(CTools.getSnowflakeId());
            videoPullurl.setBroadcastId(data.getId());
        }
        this.liveVideoPullurlsService.saveBatch(pullUrlsList);
        return data;
    }

    /**
     * 删除直播信息
     * @param data
     * @throws RuntimeException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteLiveBroadcast(LiveBroadcast data) throws RuntimeException {
        String id = data.getId();
        // 删除直播点赞信息
        this.liveThumbsUpService.remove(new LambdaQueryWrapper<LiveThumbsUp>().eq(LiveThumbsUp::getBroadcastId, id));
        // 删除直播收藏信息
        this.liveCollectService.remove(new LambdaQueryWrapper<LiveCollect>().eq(LiveCollect::getBroadcastId, id));
        // 删除直播分享信息
        this.liveShareService.remove(new LambdaQueryWrapper<LiveShare>().eq(LiveShare::getBroadcastId, id));
        // 删除直播视频信息
        this.liveVideoPullurlsService.remove(new LambdaQueryWrapper<LiveVideoPullurls>().eq(LiveVideoPullurls::getBroadcastId, id));
        // 删除直播信息
        this.removeById(id);
        // 删除小鱼直播信息
        this.xyVideoHelper.deleteLiveBroadcast(data);
        // 删除小鱼会议信息
        this.xyVideoHelper.deleteMeetingRoom(data.getMeetingRoomNumber());
    }

    @Override
    public LiveBroadcast selectLiveBroadcastById(String id){
        QueryWrapper<LiveBroadcast> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(LiveBroadcast::getId,id).eq(LiveBroadcast::getStatus, ServiceConstant.SYSTEM_ON);
        return this.liveBroadcastMapper.selectOne(wrapper);
    }

    @Override
    public String getLiveBroadcastStatus(String id) {
        LiveBroadcast liveBroadcast = selectLiveBroadcastById(id);
        if(liveBroadcast == null){
            return null;
        }
        String status = xyVideoHelper.getLiveVideoStatus(liveBroadcast.getLiveId(),liveBroadcast.getMeetingRoomNumber(),liveBroadcast.getMeetingPassword());
        liveBroadcast.setLiveState(status);
        if(StrUtil.equals(status,"END")){
            return ServiceConstant.LIVE_END;
        }else if(StrUtil.equals(status,"LIVING")){
            return ServiceConstant.LIVE_LIVING;
        }else if(StrUtil.equals(status,"PAUSE")){
            return ServiceConstant.LIVE_PAUSE;
        }else{
            return ServiceConstant.LIVE_NOSTART;
        }
    }

    @Override
    public List<LiveVideoPullurls> getLiveBroadcastVideoPullList(String id) {
        return liveVideoPullurlsService.lambdaQuery().eq(LiveVideoPullurls::getBroadcastId,id).list();
    }

    private void startBroadcast(LiveBroadcast liveBroadcast){
        xyVideoHelper.setLiveVideStatus(liveBroadcast.getLiveId(), "start", liveBroadcast.getMeetingRoomNumber(), liveBroadcast.getMeetingPassword());
    }

    @Override
    public Map<String, Object> startLiveBroadcast(String broadcastId, long deplaySecond, UserRecord userRecord) {
        LiveBroadcast liveBroadcast = liveBroadcastMapper.selectById(broadcastId);
        if(liveBroadcast == null){
            log.error("broadcastId error,live not found");
            throw new IllegalArgumentException("broadcastId error,live not found");
        }
        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("number",liveBroadcast.getMeetingRoomNumber());
        if(StrUtil.isNotBlank(liveBroadcast.getMeetingPassword())){
            paramsMap.put("pwd",Base64.encode(Secures.sm2Decrypt(liveBroadcast.getMeetingPassword()), "utf-8"));
        }
        paramsMap.put("displayName", Base64.encode(userRecord.getUserName(),"utf-8"));
        paramsMap.put("accessServer",xyApiHost);
        paramsMap.put("httpsPort",xyApiServerHttpsPort);
        paramsMap.put("httpPort",xyApiServerHttpPort);
        //paramsMap.put("token",weiXinService.getToken().getString("access_token"));
        paramsMap.put("uid",userRecord.getUserId());
        paramsMap.put("topic", Base64.encode(liveBroadcast.getTitle(), "utf-8"));
        paramsMap.put("quitWhenCallFinish",true);
        //启动延迟任务，等待执行推流
        deplayStartLiveTaskTimer.addTask(new TimerTask(() -> startBroadcast(liveBroadcast), deplaySecond * 1000));
        return paramsMap;
    }
}
